package connector

import (
	"gateway/config"
	"gateway/core"
	"gateway/util"
	"github.com/gorilla/mux"
	"go.uber.org/zap"
	"io/ioutil"
	"net/http"
	"time"
)

type httpConnector struct {
	name string
	args config.Args
}

func newHttpConnector(name string) core.Connector {
	return &httpConnector{
		name: name,
		args: config.NewArgs(),
	}
}

func (this *httpConnector) GetName() string {
	return this.name
}

func (this *httpConnector) SetArgs(args config.Args) {
	this.args.SetArgs(args)
}

func (this *httpConnector) Initialize(chain core.InboundChain) {
	r := mux.NewRouter()
	for _, in := range chain.GetInbounds() {
		args := in.GetArgs()
		path := args.Get(PATH)
		method := args.Get(METHOD)
		r.HandleFunc(path, func(w http.ResponseWriter, req *http.Request) {
			if method == "" || method == req.Method {
				msg := getMessage(req)
				if msg != nil {
					in.Receive(msg)
					w.WriteHeader(202)
					w.Write([]byte("Accepted"))
				}
			}
		})
	}
	this.start(r)
}

func (this *httpConnector) start(r http.Handler) {
	port := this.args.GetRequired(PORT)
	addr := "0.0.0.0:" + port
	server := &http.Server{
		Handler:      r,
		Addr:         addr,
		ReadTimeout:  1 * time.Minute,
		WriteTimeout: 1 * time.Minute,
	}
	config.Logger.Info("Initialize HttpConnector",
		zap.String("name", this.name),
		zap.String("port", port))
	err := server.ListenAndServe()
	if err != nil {
		config.Logger.Panic("Initialize HttpConnector error",
			zap.String("name", this.name),
			zap.Error(err))
	}
}

func getMessage(r *http.Request) core.Message {
	payload, err := ioutil.ReadAll(r.Body)
	if err != nil {
		config.Logger.Warn("Read http request body error",
			zap.String("url", r.RequestURI),
			zap.String("method", r.Method),
			zap.Error(err))
		return nil
	}
	defer util.Close(r.Body)

	msg := core.NewMessage()
	msg.SetPayload(payload)
	msg.PutContext(HTTP_METHOD, r.Method)
	msg.PutContext(HTTP_URL, r.RequestURI)
	return msg
}

func (this *httpConnector) Destroy() {
	config.Logger.Info("Destroy HttpConnector", zap.String("name", this.name))
}
